<?php
/**
 * SESSION缓存至数据库操作类库
 * @copyright Copyright&copy; 2015, 广州六象元一网络科技有限公司
 * @author 王海龙 $
 * @version  $Id: classSessionToDb.php, v 1.0, 2015-01-01 王海龙 $
 */

if (!defined('EGGMS'))
{
    die('非法进入');
}

class classSessionToDb
{
    public $db             = NULL;
    public $sessionTable  = '';

    public $maxLifeTime  = 3600; // SESSION 最大生存时间
    public $sessionName   = '';
    public $sessionId     = '';

    public $sessionExpiry = '';
    public $sessionMd5    = '';

    public $sessionCookiePath   = '/';
    public $sessionCookieDomain = '';
    public $sessionCookieSecure = false;

    public $_ip   = '';
    public $_time = 0;

    public function __construct(&$db, $sessionTable, $sessionDataTable, $sessionName = 'EGGMS', $maxLifeTime = 3600)
    {
        $this->classSessionToDb($db, $sessionTable, $sessionDataTable, $sessionName, $maxLifeTime);
    }

    public function classSessionToDb(&$db, $sessionTable, $sessionDataTable, $sessionName = 'EGGMS', $maxLifeTime = 3600)
    {
        $GLOBALS['_SESSION'] = array();

        $this->sessionCookiePath = '/';
        $this->sessionCookieDomain = '';
        $this->sessionCookieSecure = false;

        $this->sessionName       = $sessionName;
        $this->sessionTable      = $sessionTable;
        $this->sessionDataTable  = $sessionDataTable;

        $this->db  = &$db;
        $this->_ip = realIp();

        $this->maxLifeTime = $maxLifeTime;

        if (!empty($_COOKIE[$this->sessionName]))
        {
            $this->sessionId = $_COOKIE[$this->sessionName];
        }

        if ($this->sessionId)
        {
            $tmpSessionId = substr($this->sessionId, 0, 32);
            if ($this->genSessionKey($tmpSessionId) == substr($this->sessionId, 32))
            {
                $this->sessionId = $tmpSessionId;
            }
            else
            {
                $this->sessionId = '';
            }
        }

        $this->_time = time();

        if ($this->sessionId)
        {
            $this->loadSession();
        }
        else
        {
            $this->genSessionId();

            setcookie($this->sessionName, $this->sessionId . $this->genSessionKey($this->sessionId), 0, $this->sessionCookiePath, $this->sessionCookieDomain, $this->sessionCookieSecure);
        }

        register_shutdown_function(array(&$this, 'closeSession'));
    }
    /* 生成sessionId */
    public function genSessionId()
    {
        $this->sessionId = md5(uniqid(mt_rand(), true));

        return $this->insertSession();
    }
    /* 系列化sessionId */
    public function genSessionKey($sessionId)
    {
        static $ip = '';

        if ($ip == '')
        {
            $ip = substr($this->_ip, 0, strrpos($this->_ip, '.'));
        }

        return sprintf('%08x', crc32(ROOT_PATH . $ip . $sessionId));
    }
    /* 插入新session数据 */
    public function insertSession()
    {
        return $this->db->query('INSERT INTO ' . $this->sessionTable . " (sessKey, expiry, ip, data) VALUES ('" . $this->sessionId . "', '". ($this->_time + $this->maxLifeTime) ."', '". $this->_ip ."', 'a:0:{}')");
    }
    /* 读取session数据 */
    public function loadSession()
    {
        $session = $this->db->getRow('SELECT data, expiry FROM ' . $this->sessionTable . " WHERE sessKey = '" . $this->sessionId . "'");
        if (empty($session))
        {
            $this->insertSession();

            $this->sessionExpiry = 0;
            $this->sessionMd5    = '40cd750bba9870f18aada2478b24840a';
            $GLOBALS['_SESSION']  = array();
        }
        else
        {
            if (!empty($session['data']) && $this->_time <= $session['expiry'])
            {
                $this->sessionExpiry = $session['expiry'];
                $this->sessionMd5    = md5($session['data']);
                $GLOBALS['_SESSION']  = unserialize($session['data']);
            }
            else
            {
                $sessionData = $this->db->getRow('SELECT data, expiry FROM ' . $this->sessionDataTable . " WHERE sessKey = '" . $this->sessionId . "'");
                if (!empty($sessionData['data']) && $this->_time <= $sessionData['expiry'])
                {
                    $this->sessionExpiry = $sessionData['expiry'];
                    $this->sessionMd5    = md5($sessionData['data']);
                    $GLOBALS['_SESSION']  = unserialize($sessionData['data']);
                }
                else
                {
                    $this->sessionExpiry = 0;
                    $this->sessionMd5    = '40cd750bba9870f18aada2478b24840a';
                    $GLOBALS['_SESSION']  = array();
                }
            }
        }
    }
    /* 更新session数据 */
    public function updateSession()
    {
        $data        = serialize($GLOBALS['_SESSION']);
        $this->_time = time();

        if ($this->sessionMd5 == md5($data) && $this->_time < $this->sessionExpiry - $this->maxLifeTime + 10)
        {
            return true;
        }

        $data = addslashes($data);

        if (isset($data{255}))
        {
            $this->db->autoReplace($this->sessionDataTable, array('sessKey' => $this->sessionId, 'expiry' => ($this->_time + $this->maxLifeTime), 'data' => $data), array('expiry' =>($this->_time + $this->maxLifeTime),'data' => $data));

            $data = '';
        }
        return $this->db->query('UPDATE ' . $this->sessionTable . " SET expiry = '" . ($this->_time + $this->maxLifeTime) . "', ip = '" . $this->_ip . "', data = '$data' WHERE sessKey = '" . $this->sessionId . "' LIMIT 1");
    }
    /* 关闭session */
    public function closeSession()
    {
        $this->updateSession();

        /* 每当到了10整秒时，则删除无效session */
        if ((time() % 10) == 0)
        {
            $this->db->query('DELETE FROM ' . $this->sessionDataTable . ' WHERE expiry < ' . $this->_time);
            $this->db->query('DELETE FROM ' . $this->sessionTable . ' WHERE expiry < ' . $this->_time);
        }

        return true;
    }
    /* 获取sessionId */
    public function getSessionId()
    {
        return $this->sessionId;
    }
    /* 获取用户量 */
    public function getUserCount()
    {
        return $this->db->getOne('SELECT count(*) FROM ' . $this->sessionTable);
    }
}
